package com.fxl.majiang.enums;

import com.fxl.majiang.exception.CustomException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.SneakyThrows;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author fengxinglei
 * @date 2022/8/1 14:30
 * @description 麻将牌枚举
 */
@Getter
@AllArgsConstructor
public enum TilesEnum {
    YI_WAN(1, CardTypeEnum.WAN, "一万"),
    ER_WAN(2, CardTypeEnum.WAN, "二万"),
    SAN_WAN(3, CardTypeEnum.WAN, "三万"),
    SI_WAN(4, CardTypeEnum.WAN, "四万"),
    WU_WAN(5, CardTypeEnum.WAN, "五万"),
    LIU_WAN(6, CardTypeEnum.WAN, "六万"),
    QI_WAN(7, CardTypeEnum.WAN, "七万"),
    BA_WAN(8, CardTypeEnum.WAN, "八万"),
    JIU_WAN(9, CardTypeEnum.WAN, "九万"),
    YI_TIAO(1, CardTypeEnum.TIAO, "一条"),
    ER_TIAO(2, CardTypeEnum.TIAO, "二条"),
    SAN_TIAO(3, CardTypeEnum.TIAO, "三条"),
    SI_TIAO(4, CardTypeEnum.TIAO, "四条"),
    WU_TIAO(5, CardTypeEnum.TIAO, "五条"),
    LIU_TIAO(6, CardTypeEnum.TIAO, "六条"),
    QI_TIAO(7, CardTypeEnum.TIAO, "七条"),
    BA_TIAO(8, CardTypeEnum.TIAO, "八条"),
    JIU_TIAO(9, CardTypeEnum.TIAO, "九条"),
    YI_TONG(1, CardTypeEnum.TONG, "一筒"),
    ER_TONG(2, CardTypeEnum.TONG, "二筒"),
    SAN_TONG(3, CardTypeEnum.TONG, "三筒"),
    SI_TONG(4, CardTypeEnum.TONG, "四筒"),
    WU_TONG(5, CardTypeEnum.TONG, "五筒"),
    LIU_TONG(6, CardTypeEnum.TONG, "六筒"),
    QI_TONG(7, CardTypeEnum.TONG, "七筒"),
    BA_TONG(8, CardTypeEnum.TONG, "八筒"),
    JIU_TONG(9, CardTypeEnum.TONG, "九筒"),
    DONG_FENG(1, CardTypeEnum.FENG, "东风"),
    NAN_FENG(2, CardTypeEnum.FENG, "南风"),
    XI_FENG(3, CardTypeEnum.FENG, "西风"),
    BEI_FENG(4, CardTypeEnum.FENG, "北风"),
    HONG_ZHONG(5, CardTypeEnum.ZI, "红中"),
    FA_CAI(6, CardTypeEnum.ZI, "发财"),
    BAI_BAN(7, CardTypeEnum.BAI_BAN, "白板"),
    MEI(1, CardTypeEnum.HEI_HUA, "梅"),
    LAN(2, CardTypeEnum.HEI_HUA, "兰"),
    ZHU(3, CardTypeEnum.HEI_HUA, "竹"),
    JU(4, CardTypeEnum.HEI_HUA, "菊"),
    CHUN(1, CardTypeEnum.HONG_HUA, "春"),
    XIA(2, CardTypeEnum.HONG_HUA, "夏"),
    QIU(3, CardTypeEnum.HONG_HUA, "秋"),
    DONG(4, CardTypeEnum.HONG_HUA, "冬"),
    ;

    private int code;

    private CardTypeEnum type;

    private String name;

    // 万字牌 顺序列表
    private static List<TilesEnum> WAN_LIST = new ArrayList<>();
    // 条牌 顺序列表
    private static List<TilesEnum> TIAO_LIST = new ArrayList<>();
    // 筒子牌 顺序列表
    private static List<TilesEnum> TONG_LIST = new ArrayList<>();
    // 风牌
    private static List<TilesEnum> FENG_LIST = new ArrayList<>();
    // 字牌
    private static List<TilesEnum> ZI_LIST = new ArrayList<>();
    // 白板
    private static List<TilesEnum> BAI_BAN_LIST = new ArrayList<>();
    // 黑花牌
    private static List<TilesEnum> HEI_HUA_LIST = new ArrayList<>();
    // 红花牌
    private static List<TilesEnum> HONG_HUA_LIST = new ArrayList<>();

    // 万字牌ABC牌组集合
    private static List<List<TilesEnum>> WAN_ABC_GROUP_LIST = new ArrayList<>();
    // 条字牌ABC牌组集合
    private static List<List<TilesEnum>> TIAO_ABC_GROUP_LIST = new ArrayList<>();
    // 条字牌ABC牌组集合
    private static List<List<TilesEnum>> TONG_ABC_GROUP_LIST = new ArrayList<>();

    static {
        initList();
        // 加载ABC牌组
        initABCGroupList();
    }

    /**
     * 加载列表
     */
    private static void initList() {
        for (TilesEnum tile : values()) {
            CardTypeEnum _type = tile.getType();
            if (CardTypeEnum.WAN.equals(_type)) {
                WAN_LIST.add(tile);
            } else if (CardTypeEnum.TIAO.equals(_type)) {
                TIAO_LIST.add(tile);
            } else if (CardTypeEnum.TONG.equals(_type)) {
                TONG_LIST.add(tile);
            } else if (CardTypeEnum.FENG.equals(_type)) {
                FENG_LIST.add(tile);
            } else if (CardTypeEnum.ZI.equals(_type)) {
                ZI_LIST.add(tile);
            } else if (CardTypeEnum.HEI_HUA.equals(_type)) {
                HEI_HUA_LIST.add(tile);
            } else if (CardTypeEnum.HONG_HUA.equals(_type)) {
                HONG_HUA_LIST.add(tile);
            } else if (CardTypeEnum.BAI_BAN.equals(_type)) {
                BAI_BAN_LIST.add(tile);
            }
        }
        WAN_LIST = WAN_LIST.stream().sorted(Comparator.comparing(TilesEnum::getCode)).collect(Collectors.toList());
        TIAO_LIST = TIAO_LIST.stream().sorted(Comparator.comparing(TilesEnum::getCode)).collect(Collectors.toList());
        TONG_LIST = TONG_LIST.stream().sorted(Comparator.comparing(TilesEnum::getCode)).collect(Collectors.toList());
        FENG_LIST = FENG_LIST.stream().sorted(Comparator.comparing(TilesEnum::getCode)).collect(Collectors.toList());
        ZI_LIST = ZI_LIST.stream().sorted(Comparator.comparing(TilesEnum::getCode)).collect(Collectors.toList());
        HEI_HUA_LIST = HEI_HUA_LIST.stream().sorted(Comparator.comparing(TilesEnum::getCode)).collect(Collectors.toList());
        HONG_HUA_LIST = HONG_HUA_LIST.stream().sorted(Comparator.comparing(TilesEnum::getCode)).collect(Collectors.toList());
        BAI_BAN_LIST = BAI_BAN_LIST.stream().sorted(Comparator.comparing(TilesEnum::getCode)).collect(Collectors.toList());
    }

    /**
     * 初始化ABC牌组列表
     */
    private static void initABCGroupList() {
        for (int i = 0; i<7; i++) {
            // 万
            List<TilesEnum> wanGroup = new ArrayList<>();
            wanGroup.add(WAN_LIST.get(i));
            wanGroup.add(WAN_LIST.get(i+1));
            wanGroup.add(WAN_LIST.get(i+2));
            WAN_ABC_GROUP_LIST.add(wanGroup);
            // 条
            List<TilesEnum> tiaoGroup = new ArrayList<>();
            tiaoGroup.add(TIAO_LIST.get(i));
            tiaoGroup.add(TIAO_LIST.get(i+1));
            tiaoGroup.add(TIAO_LIST.get(i+2));
            TIAO_ABC_GROUP_LIST.add(tiaoGroup);
            // 筒
            List<TilesEnum> tongGroup = new ArrayList<>();
            tongGroup.add(TONG_LIST.get(i));
            tongGroup.add(TONG_LIST.get(i+1));
            tongGroup.add(TONG_LIST.get(i+2));
            TONG_ABC_GROUP_LIST.add(tongGroup);
        }
    }

    /**
     * 获取某个牌型的所有牌
     * @param type
     * @return
     */
    public static List<TilesEnum> getByType(CardTypeEnum type) {
        if (type == CardTypeEnum.WAN) {
            return WAN_LIST;
        } else if (type == CardTypeEnum.TIAO) {
            return TIAO_LIST;
        } else if (type == CardTypeEnum.TONG) {
            return TONG_LIST;
        } else if (type == CardTypeEnum.FENG) {
            return FENG_LIST;
        } else if (type == CardTypeEnum.BAI_BAN) {
            return BAI_BAN_LIST;
        } else if (type == CardTypeEnum.HEI_HUA) {
            return HEI_HUA_LIST;
        } else if (type == CardTypeEnum.HONG_HUA) {
            return HONG_HUA_LIST;
        }
        return null;
    }

    /**
     * 获取吃牌牌组
     * @param type
     * @return
     */
    public static List<List<TilesEnum>> getABCGroupList(CardTypeEnum type) {
        if (type == CardTypeEnum.WAN) {
            return WAN_ABC_GROUP_LIST;
        } else if (type == CardTypeEnum.TIAO) {
            return TIAO_ABC_GROUP_LIST;
        } else if (type == CardTypeEnum.TONG) {
            return TONG_ABC_GROUP_LIST;
        }
        return null;
    }

    /**
     * 获取可以吃这张牌的牌列表
     * @param it
     * @return
     */
    @SneakyThrows
    public static List<List<TilesEnum>> getChiItGroupList(TilesEnum it) {
        CardTypeEnum type = it.getType();
        if (type != CardTypeEnum.WAN && type != CardTypeEnum.TONG && type != CardTypeEnum.TIAO) {
            return new ArrayList<>();
        }
        // 获取吃牌牌组列表
        List<List<TilesEnum>> groupList = getABCGroupList(type);
        List<List<TilesEnum>> result = new ArrayList<>();
        for (List<TilesEnum> group : groupList) {
            // 如果牌组包含这张牌，则代表该牌组可以吃
            if (group.contains(it)) {
                result.add(group);
            }
        }
        return result;
    }

    /**
     * 构建杠牌组合
     * @param tile
     * @return
     */
    public static List<TilesEnum> buildGang(TilesEnum tile) {
        if (tile.getType() == CardTypeEnum.HEI_HUA || tile.getType() == CardTypeEnum.HONG_HUA) {
            return new ArrayList<>();
        }
        List<TilesEnum> tiles = new ArrayList<>();
        tiles.add(tile);
        tiles.add(tile);
        tiles.add(tile);
        tiles.add(tile);
        return tiles;
    }

    /**
     * 是否含有花牌或者白板
     * @param tiles
     * @return
     */
    public static boolean haveHuaOrBaiBan(List<TilesEnum> tiles) {
        for (TilesEnum tile: tiles) {
            if (tile.getType() == CardTypeEnum.HEI_HUA || tile.getType() == CardTypeEnum.HONG_HUA ||  tile.getType() == CardTypeEnum.BAI_BAN) {
                return true;
            }
        }
        return false;
    }
}
